/*!
 * jQuery Color Animations v2.0pre
 * http://jquery.org/
 *
 * Copyright 2011 John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function (jQuery, undefined) {
  var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color outlineColor".split(
      " "
    ),
    // plusequals test for += 100 -= 100
    rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
    // a set of RE's that can match strings and generate color tuples.
    stringParsers = [
      {
        re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
        parse: function (execResult) {
          return [execResult[1], execResult[2], execResult[3], execResult[4]];
        },
      },
      {
        re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
        parse: function (execResult) {
          return [
            2.55 * execResult[1],
            2.55 * execResult[2],
            2.55 * execResult[3],
            execResult[4],
          ];
        },
      },
      {
        re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
        parse: function (execResult) {
          return [
            parseInt(execResult[1], 16),
            parseInt(execResult[2], 16),
            parseInt(execResult[3], 16),
          ];
        },
      },
      {
        re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,
        parse: function (execResult) {
          return [
            parseInt(execResult[1] + execResult[1], 16),
            parseInt(execResult[2] + execResult[2], 16),
            parseInt(execResult[3] + execResult[3], 16),
          ];
        },
      },
      {
        re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
        space: "hsla",
        parse: function (execResult) {
          return [
            execResult[1],
            execResult[2] / 100,
            execResult[3] / 100,
            execResult[4],
          ];
        },
      },
    ],
    // jQuery.Color( )
    color = (jQuery.Color = function (color, green, blue, alpha) {
      return new jQuery.Color.fn.parse(color, green, blue, alpha);
    }),
    spaces = {
      rgba: {
        cache: "_rgba",
        props: {
          red: {
            idx: 0,
            type: "byte",
            empty: true,
          },
          green: {
            idx: 1,
            type: "byte",
            empty: true,
          },
          blue: {
            idx: 2,
            type: "byte",
            empty: true,
          },
          alpha: {
            idx: 3,
            type: "percent",
            def: 1,
          },
        },
      },
      hsla: {
        cache: "_hsla",
        props: {
          hue: {
            idx: 0,
            type: "degrees",
            empty: true,
          },
          saturation: {
            idx: 1,
            type: "percent",
            empty: true,
          },
          lightness: {
            idx: 2,
            type: "percent",
            empty: true,
          },
        },
      },
    },
    propTypes = {
      byte: {
        floor: true,
        min: 0,
        max: 255,
      },
      percent: {
        min: 0,
        max: 1,
      },
      degrees: {
        mod: 360,
        floor: true,
      },
    },
    rgbaspace = spaces.rgba.props,
    support = (color.support = {}),
    // colors = jQuery.Color.names
    colors,
    // local aliases of functions called often
    each = jQuery.each;

  spaces.hsla.props.alpha = rgbaspace.alpha;

  function clamp(value, prop, alwaysAllowEmpty) {
    var type = propTypes[prop.type] || {},
      allowEmpty = prop.empty || alwaysAllowEmpty;

    if (allowEmpty && value == null) {
      return null;
    }
    if (prop.def && value == null) {
      return prop.def;
    }
    if (type.floor) {
      value = ~~value;
    } else {
      value = parseFloat(value);
    }
    if (value == null || isNaN(value)) {
      return prop.def;
    }
    if (type.mod) {
      value = value % type.mod;
      // -10 -> 350
      return value < 0 ? type.mod + value : value;
    }

    // for now all property types without mod have min and max
    return type.min > value ? type.min : type.max < value ? type.max : value;
  }

  function stringParse(string) {
    var inst = color(),
      rgba = (inst._rgba = []);

    string = string.toLowerCase();

    each(stringParsers, function (i, parser) {
      var match = parser.re.exec(string),
        values = match && parser.parse(match),
        parsed,
        spaceName = parser.space || "rgba",
        cache = spaces[spaceName].cache;

      if (values) {
        parsed = inst[spaceName](values);

        // if this was an rgba parse the assignment might happen twice
        // oh well....
        inst[cache] = parsed[cache];
        rgba = inst._rgba = parsed._rgba;

        // exit each( stringParsers ) here because we matched
        return false;
      }
    });

    // Found a stringParser that handled it
    if (rgba.length !== 0) {
      // if this came from a parsed string, force "transparent" when alpha is 0
      // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
      if (Math.max.apply(Math, rgba) === 0) {
        jQuery.extend(rgba, colors.transparent);
      }
      return inst;
    }

    // named colors / default - filter back through parse function
    if ((string = colors[string])) {
      return string;
    }
  }

  color.fn = color.prototype = {
    constructor: color,
    parse: function (red, green, blue, alpha) {
      if (red === undefined) {
        this._rgba = [null, null, null, null];
        return this;
      }
      if (red instanceof jQuery || red.nodeType) {
        red = red instanceof jQuery ? red.css(green) : jQuery(red).css(green);
        green = undefined;
      }

      var inst = this,
        type = jQuery.type(red),
        rgba = (this._rgba = []),
        source;

      // more than 1 argument specified - assume ( red, green, blue, alpha )
      if (green !== undefined) {
        red = [red, green, blue, alpha];
        type = "array";
      }

      if (type === "string") {
        return this.parse(stringParse(red) || colors._default);
      }

      if (type === "array") {
        each(rgbaspace, function (key, prop) {
          rgba[prop.idx] = clamp(red[prop.idx], prop);
        });
        return this;
      }

      if (type === "object") {
        if (red instanceof color) {
          each(spaces, function (spaceName, space) {
            if (red[space.cache]) {
              inst[space.cache] = red[space.cache].slice();
            }
          });
        } else {
          each(spaces, function (spaceName, space) {
            each(space.props, function (key, prop) {
              var cache = space.cache;

              // if the cache doesn't exist, and we know how to convert
              if (!inst[cache] && space.to) {
                // if the value was null, we don't need to copy it
                // if the key was alpha, we don't need to copy it either
                if (red[key] == null || key === "alpha") {
                  return;
                }
                inst[cache] = space.to(inst._rgba);
              }

              // this is the only case where we allow nulls for ALL properties.
              // call clamp with alwaysAllowEmpty
              inst[cache][prop.idx] = clamp(red[key], prop, true);
            });
          });
        }
        return this;
      }
    },
    is: function (compare) {
      var is = color(compare),
        same = true,
        myself = this;

      each(spaces, function (_, space) {
        var isCache = is[space.cache],
          localCache;
        if (isCache) {
          localCache =
            myself[space.cache] || (space.to && space.to(myself._rgba)) || [];
          each(space.props, function (_, prop) {
            if (isCache[prop.idx] != null) {
              same = isCache[prop.idx] === localCache[prop.idx];
              return same;
            }
          });
        }
        return same;
      });
      return same;
    },
    _space: function () {
      var used = [],
        inst = this;
      each(spaces, function (spaceName, space) {
        if (inst[space.cache]) {
          used.push(spaceName);
        }
      });
      return used.pop();
    },
    transition: function (other, distance) {
      var end = color(other),
        spaceName = end._space(),
        space = spaces[spaceName],
        start = this[space.cache] || space.to(this._rgba),
        result = start.slice();

      end = end[space.cache];
      each(space.props, function (key, prop) {
        var index = prop.idx,
          startValue = start[index],
          endValue = end[index],
          type = propTypes[prop.type] || {};

        // if null, don't override start value
        if (endValue === null) {
          return;
        }
        // if null - use end
        if (startValue === null) {
          result[index] = endValue;
        } else {
          if (type.mod) {
            if (endValue - startValue > type.mod / 2) {
              startValue += type.mod;
            } else if (startValue - endValue > type.mod / 2) {
              startValue -= type.mod;
            }
          }
          result[prop.idx] = clamp(
            (endValue - startValue) * distance + startValue,
            prop
          );
        }
      });
      return this[spaceName](result);
    },
    blend: function (opaque) {
      // if we are already opaque - return ourself
      if (this._rgba[3] === 1) {
        return this;
      }

      var rgb = this._rgba.slice(),
        a = rgb.pop(),
        blend = color(opaque)._rgba;

      return color(
        jQuery.map(rgb, function (v, i) {
          return (1 - a) * blend[i] + a * v;
        })
      );
    },
    toRgbaString: function () {
      var prefix = "rgba(",
        rgba = jQuery.map(this._rgba, function (v, i) {
          return v == null ? (i > 2 ? 1 : 0) : v;
        });

      if (rgba[3] === 1) {
        rgba.pop();
        prefix = "rgb(";
      }

      return prefix + rgba.join(",") + ")";
    },
    toHslaString: function () {
      var prefix = "hsla(",
        hsla = jQuery.map(this.hsla(), function (v, i) {
          if (v == null) {
            v = i > 2 ? 1 : 0;
          }

          // catch 1 and 2
          if (i && i < 3) {
            v = Math.round(v * 100) + "%";
          }
          return v;
        });

      if (hsla[3] === 1) {
        hsla.pop();
        prefix = "hsl(";
      }
      return prefix + hsla.join(",") + ")";
    },
    toHexString: function (includeAlpha) {
      var rgba = this._rgba.slice(),
        alpha = rgba.pop();

      if (includeAlpha) {
        rgba.push(~~(alpha * 255));
      }

      return (
        "#" +
        jQuery
          .map(rgba, function (v, i) {
            // default to 0 when nulls exist
            v = (v || 0).toString(16);
            return v.length === 1 ? "0" + v : v;
          })
          .join("")
      );
    },
    toString: function () {
      return this._rgba[3] === 0 ? "transparent" : this.toRgbaString();
    },
  };
  color.fn.parse.prototype = color.fn;

  // hsla conversions adapted from:
  // http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/Color.js&d=7&l=193

  function hue2rgb(p, q, h) {
    h = (h + 1) % 1;
    if (h * 6 < 1) {
      return p + (q - p) * 6 * h;
    }
    if (h * 2 < 1) {
      return q;
    }
    if (h * 3 < 2) {
      return p + (q - p) * (2 / 3 - h) * 6;
    }
    return p;
  }

  spaces.hsla.to = function (rgba) {
    if (rgba[0] == null || rgba[1] == null || rgba[2] == null) {
      return [null, null, null, rgba[3]];
    }
    var r = rgba[0] / 255,
      g = rgba[1] / 255,
      b = rgba[2] / 255,
      a = rgba[3],
      max = Math.max(r, g, b),
      min = Math.min(r, g, b),
      diff = max - min,
      add = max + min,
      l = add * 0.5,
      h,
      s;

    if (min === max) {
      h = 0;
    } else if (r === max) {
      h = (60 * (g - b)) / diff + 360;
    } else if (g === max) {
      h = (60 * (b - r)) / diff + 120;
    } else {
      h = (60 * (r - g)) / diff + 240;
    }

    if (l === 0 || l === 1) {
      s = l;
    } else if (l <= 0.5) {
      s = diff / add;
    } else {
      s = diff / (2 - add);
    }
    return [Math.round(h) % 360, s, l, a == null ? 1 : a];
  };

  spaces.hsla.from = function (hsla) {
    if (hsla[0] == null || hsla[1] == null || hsla[2] == null) {
      return [null, null, null, hsla[3]];
    }
    var h = hsla[0] / 360,
      s = hsla[1],
      l = hsla[2],
      a = hsla[3],
      q = l <= 0.5 ? l * (1 + s) : l + s - l * s,
      p = 2 * l - q,
      r,
      g,
      b;

    return [
      Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
      Math.round(hue2rgb(p, q, h) * 255),
      Math.round(hue2rgb(p, q, h - 1 / 3) * 255),
      a,
    ];
  };

  each(spaces, function (spaceName, space) {
    var props = space.props,
      cache = space.cache,
      to = space.to,
      from = space.from;

    // makes rgba() and hsla()
    color.fn[spaceName] = function (value) {
      // generate a cache for this space if it doesn't exist
      if (to && !this[cache]) {
        this[cache] = to(this._rgba);
      }
      if (value === undefined) {
        return this[cache].slice();
      }

      var type = jQuery.type(value),
        arr = type === "array" || type === "object" ? value : arguments,
        local = this[cache].slice(),
        ret;

      each(props, function (key, prop) {
        var val = arr[type === "object" ? key : prop.idx];
        if (val == null) {
          val = local[prop.idx];
        }
        local[prop.idx] = clamp(val, prop);
      });

      if (from) {
        ret = color(from(local));
        ret[cache] = local;
        return ret;
      } else {
        return color(local);
      }
    };

    // makes red() green() blue() alpha() hue() saturation() lightness()
    each(props, function (key, prop) {
      // alpha is included in more than one space
      if (color.fn[key]) {
        return;
      }
      color.fn[key] = function (value) {
        var vtype = jQuery.type(value),
          fn = key === "alpha" ? (this._hsla ? "hsla" : "rgba") : spaceName,
          local = this[fn](),
          cur = local[prop.idx],
          match;

        if (vtype === "undefined") {
          return cur;
        }

        if (vtype === "function") {
          value = value.call(this, cur);
          vtype = jQuery.type(value);
        }
        if (value == null && prop.empty) {
          return this;
        }
        if (vtype === "string") {
          match = rplusequals.exec(value);
          if (match) {
            value = cur + parseFloat(match[2]) * (match[1] === "+" ? 1 : -1);
          }
        }
        local[prop.idx] = value;
        return this[fn](local);
      };
    });
  });

  // add .fx.step functions
  each(stepHooks, function (i, hook) {
    jQuery.cssHooks[hook] = {
      set: function (elem, value) {
        var parsed, backgroundColor, curElem;

        if (jQuery.type(value) !== "string" || (parsed = stringParse(value))) {
          value = color(parsed || value);
          if (!support.rgba && value._rgba[3] !== 1) {
            curElem = hook === "backgroundColor" ? elem.parentNode : elem;
            do {
              backgroundColor = jQuery.curCSS(curElem, "backgroundColor");
            } while (
              (backgroundColor === "" || backgroundColor === "transparent") &&
              (curElem = curElem.parentNode) &&
              curElem.style
            );

            value = value.blend(
              backgroundColor && backgroundColor !== "transparent"
                ? backgroundColor
                : "_default"
            );
          }

          value = value.toRgbaString();
        }
        elem.style[hook] = value;
      },
    };
    jQuery.fx.step[hook] = function (fx) {
      if (!fx.colorInit) {
        fx.start = color(fx.elem, hook);
        fx.end = color(fx.end);
        fx.colorInit = true;
      }
      jQuery.cssHooks[hook].set(fx.elem, fx.start.transition(fx.end, fx.pos));
    };
  });

  // detect rgba support
  jQuery(function () {
    var div = document.createElement("div"),
      div_style = div.style;

    div_style.cssText = "background-color:rgba(1,1,1,.5)";
    support.rgba = div_style.backgroundColor.indexOf("rgba") > -1;
  });

  // Some named colors to work with
  // From Interface by Stefan Petre
  // http://interface.eyecon.ro/
  colors = jQuery.Color.names = {
    aqua: "#00ffff",
    azure: "#f0ffff",
    beige: "#f5f5dc",
    black: "#000000",
    blue: "#0000ff",
    brown: "#a52a2a",
    cyan: "#00ffff",
    darkblue: "#00008b",
    darkcyan: "#008b8b",
    darkgrey: "#a9a9a9",
    darkgreen: "#006400",
    darkkhaki: "#bdb76b",
    darkmagenta: "#8b008b",
    darkolivegreen: "#556b2f",
    darkorange: "#ff8c00",
    darkorchid: "#9932cc",
    darkred: "#8b0000",
    darksalmon: "#e9967a",
    darkviolet: "#9400d3",
    fuchsia: "#ff00ff",
    gold: "#ffd700",
    green: "#008000",
    indigo: "#4b0082",
    khaki: "#f0e68c",
    lightblue: "#add8e6",
    lightcyan: "#e0ffff",
    lightgreen: "#90ee90",
    lightgrey: "#d3d3d3",
    lightpink: "#ffb6c1",
    lightyellow: "#ffffe0",
    lightblack: "#000",
    lime: "#00ff00",
    magenta: "#ff00ff",
    maroon: "#800000",
    navy: "#000080",
    olive: "#808000",
    orange: "#ffa500",
    pink: "#ffc0cb",
    purple: "#800080",
    violet: "#800080",
    red: "#ff0000",
    silver: "#c0c0c0",
    white: "#ffffff",
    yellow: "#ffff00",
    black: "#000",
    transparent: [null, null, null, 0],
    _default: "#ffffff",
  };
})(jQuery);
